package com.xiaomaoguai.fcp.pre.kepler.router.router;

import com.rits.cloning.Cloner;
import com.xiaomaoguai.fcp.pre.kepler.router.buf.Buf;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.RouterInfo;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.Handler;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.api.HandlerContext;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.enums.HandleResult;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlercontext.AbstractHandlerContext;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlercontext.DefaultHandlerContext;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlercontext.TailContext;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlers.EmptyHeadHandler;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlers.EmptyTailHandler;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.handlers.TailHandler;
import com.xiaomaoguai.fcp.pre.kepler.router.handler.spi.HandlerManager;
import org.apache.commons.lang3.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;

/**
 * RouterPipeline是一个特殊的handlerContext 它的handler就是头handler 持有buf
 * 管理当前责任链所有的handlerContext 返回结果通过getResp获取
 *
 * @param <I>
 * @param <O>
 * @author DH
 */
public class RouterPipeline<I, O> extends AbstractHandlerContext<I> implements HandlerContext<I> {

    private final static Cloner cloner = new Cloner();

    /**
     * 默认headHandler
     * 用以创建新责任链时替换空handler
     */
    private Handler defaultHeadHandler;

    private TailHandler tailHandler;

    private HandlerContext[] handlerContexts;

    private TailContext<O> tail;

    private Buf buf;

    private RouterConfig routerConfig;

    private boolean isSinglePipe = Boolean.FALSE;

    private String routerName;

    private List<String> lockKeys = new ArrayList<>(10);

    public RouterPipeline(Handler<I> headHandler, TailHandler tailHandler, RouterConfig routerConfig) {
        this(headHandler, tailHandler, routerConfig, null);
    }

    public RouterPipeline(Handler<I> headHandler, TailHandler tailHandler, RouterConfig routerConfig,
                          String routerName) {
        this.handler = headHandler;
        this.tailHandler = tailHandler;
        this.routerConfig = routerConfig;
        this.routerName = routerName;
    }

    public List<RouterInfo> getRouterInfos(String routerName) {
        return routerConfig.getRouterInfos(routerName);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    public RouterPipeline<I, O> init(List<RouterInfo> routerInfos) {
        this.setRouterInfo(new RouterInfo("HEAD"));
        fillHandlerContexts(routerInfos.size() + 2);
        setNext(handlerContexts[1]);
        int order = 1;
        for (RouterInfo routerInfo : routerInfos) {
            routerInfo.build();
            final String name = routerInfo.getName();
            Handler handler = HandlerManager.getHandler(name);
            handlerContexts[order].setHandler(handler).setRouterInfo(routerInfo).setNext(handlerContexts[order++ + 1]);
        }
        return this;
    }

    /**
     * 填充handlerContext
     *
     * @param length
     */
    private void fillHandlerContexts(int length) {
        handlerContexts = new HandlerContext[length];
        handlerContexts[0] = this;
        for (int i = 1; i < length - 1; i++) {
            handlerContexts[i] = new DefaultHandlerContext(this);
        }
        tail = new TailContext<O>(this, tailHandler);
        tail.setRouterInfo(new RouterInfo("TAIL"));
        handlerContexts[length - 1] = tail;
    }

    /**
     * 指定order单个调用 可用于单元测试
     *
     * @param order
     * @param buf
     */
    public void invokeHandler(int order, Buf buf) {
        this.buf = buf;
        buf.setCurrentRouterName(routerName);
        handlerContexts[order].syncHandler();
    }

    /**
     * 从指定order开始调用责任链
     *
     * @param order
     * @param buf
     */
    public void invokeHandlers(int order, Buf buf) {
        this.buf = buf;
        buf.setCurrentRouterName(routerName);
        handlerContexts[order].invokeHandler();
    }

    /**
     * 推荐调用责任链入口 rpc请求且callback为yes时，同返回步
     *
     * @param req
     */
    public Buf fireHandlers(I req) {
        setInnerParam(req);
        return invokeHandler();
    }

    public TreeMap<String, HandleResult> getHandleResults() {
        TreeMap<String, HandleResult> handleResults = new TreeMap<String, HandleResult>();
        for (HandlerContext handlerContext : handlerContexts) {
            handleResults.put(handlerContext.name(), handlerContext.getHandlerResult());
        }
        return handleResults;
    }

    public O getResp() {
        return tail.getOutParam();
    }

    @Override
    public RouterPipeline<I, O> getRouter() {
        return this;
    }

    /**
     * 在指定order添加新的handlerContext
     *
     * @param order
     * @param hc
     * @return
     */
    public RouterPipeline<I, O> addHandlerContext(int order, HandlerContext hc) {
        HandlerContext[] newHadlerContexts = new HandlerContext[handlerContexts.length + 1];
        for (int i = 0, j = 0; i < newHadlerContexts.length; i++) {
            if (i == order) {
                newHadlerContexts[i] = hc;
                continue;
            }
            newHadlerContexts[i] = handlerContexts[j];
            RouterInfo orRouterInfo = newHadlerContexts[i].getRouterInfo();
            if (orRouterInfo != null) {
                RouterInfo newRouterInfo = cloner.deepClone(orRouterInfo);
                newRouterInfo.setOrder(100 + i);
                newHadlerContexts[i].setRouterInfo(newRouterInfo);
            }
            j++;
        }
        handlerContexts = newHadlerContexts;
        return this;
    }

    public RouterPipeline<I, O> addHandlerContexts(int order, List<HandlerContext<?>> hcs) {
        HandlerContext[] newHadlerContexts = new HandlerContext[handlerContexts.length + hcs.size()];
        for (int i = 0, j = 0; i < newHadlerContexts.length; i++) {
            if (i == order) {
                for (HandlerContext handlerContext : hcs) {
                    newHadlerContexts[i] = handlerContext;
                    i++;
                }
            }
            newHadlerContexts[i] = handlerContexts[j];
            RouterInfo orRouterInfo = newHadlerContexts[i].getRouterInfo();
            if (orRouterInfo != null) {
                RouterInfo newRouterInfo = cloner.deepClone(orRouterInfo);
                newRouterInfo.setOrder(100 + i);
                newHadlerContexts[i].setRouterInfo(newRouterInfo);
                newHadlerContexts[i].setRouterInfo(newRouterInfo);
            }
            j++;
        }
        handlerContexts = newHadlerContexts;
        return this;
    }

    /**
     * 创建一个只有一个HandlerContext的责任链 handler调用线程安全
     *
     * @param handlerContext
     * @return
     */
    public RouterPipeline<Buf, Buf> newSingleHandlerPipe(HandlerContext<?> handlerContext) {
        RouterPipeline<Buf, Buf> singleHandlerPipe = new RouterPipeline<Buf, Buf>(new EmptyHeadHandler(),
                new EmptyTailHandler(), routerConfig, handlerContext.getRouter().getRouterName());
        singleHandlerPipe.setDefaultHeadHandler(defaultHeadHandler);
        singleHandlerPipe.setRouterInfo(new RouterInfo("HEAD"));
        singleHandlerPipe.fillHandlerContexts(3);
        singleHandlerPipe.setNext(singleHandlerPipe.getHC(1).setHandler(handlerContext.getHandler())
                .setRouterInfo(handlerContext.getRouterInfo())).setNext(singleHandlerPipe.getHC(2));
        singleHandlerPipe.setSinglePipe(Boolean.TRUE);
        return singleHandlerPipe;
    }

    /**
     * 创建一个新pipe
     *
     * @param routerName router名称
     * @return
     */
    public RouterPipeline newPipe(String routerName) {
        return this.newPipe(routerName, tailHandler);
    }

    /**
     * 重载创建一个新pipe
     *
     * @param routerName        router名称
     * @param defineTailHandler 尾节点实例
     * @return
     */
    public RouterPipeline newPipe(String routerName, TailHandler defineTailHandler) {
        RouterPipeline newPipe = new RouterPipeline(this.defaultHeadHandler,
                ObjectUtils.defaultIfNull(defineTailHandler, tailHandler), routerConfig, routerName);
        newPipe.setDefaultHeadHandler(defaultHeadHandler);
        return newPipe.init(routerConfig.getRouterInfos(routerName));
    }

    public RouterConfig getRouterConfig() {
        return routerConfig;
    }

    public String getRouterName() {
        return routerName;
    }

    public HandlerContext getHC(int order) {
        return handlerContexts[order];
    }

    public void setRouterName(String routerName) {
        this.routerName = routerName;
    }

    public boolean isSinglePipe() {
        return isSinglePipe;
    }

    public RouterPipeline<I, O> setSinglePipe(boolean isSinglePipe) {
        this.isSinglePipe = isSinglePipe;
        return this;
    }

    /**
     * 克隆一个新的RouterPipe
     */
    @Override
    public RouterPipeline<I, O> clone() {
        RouterPipeline<I, O> newPipe = new RouterPipeline<I, O>(this.handler, this.tailHandler, this.routerConfig,
                routerName);
        newPipe.setDefaultHeadHandler(this.defaultHeadHandler);
        return newPipe.init(this.handlerContexts);
    }

    /**
     * 克隆一个新的RouterPipe时初始化
     *
     * @param initHadlerContexts
     * @return
     */
    private RouterPipeline<I, O> init(HandlerContext[] initHadlerContexts) {
        this.setRouterInfo(initHadlerContexts[0].getRouterInfo());
        fillHandlerContexts(initHadlerContexts.length);
        setNext(this.handlerContexts[1]);
        for (int i = 1; i < initHadlerContexts.length - 1; i++) {
            this.handlerContexts[i].setHandler(initHadlerContexts[i].getHandler())
                    .setRouterInfo(initHadlerContexts[i].getRouterInfo()).setNext(this.handlerContexts[i + 1]);
        }
        return this;
    }

    @Override
    public TailContext<O> getLast() {
        return tail;
    }

    @Override
    public Buf getBuf() {
        return buf;
    }

    public RouterPipeline<I, O> setBuf(Buf buf) {
        buf.setCurrentRouterName(routerName);
        this.buf = buf;
        return this;
    }

    public HandlerContext<Buf> setLast(TailContext<O> tailContext) {
        this.tail = tailContext;
        tailHandler = (TailHandler) tailContext.getHandler();
        handlerContexts[handlerContexts.length - 1] = tailContext;
        return tailContext;
    }

    public List<String> getLockKeys() {
        return lockKeys;
    }

    public void setLockKeys(List<String> lockKeys) {
        this.lockKeys = lockKeys;
    }

    public void addLockKey(String lockKey) {
        this.lockKeys.add(lockKey);
    }

    public void removeLockKey(String lockKey) {
        this.lockKeys.remove(lockKey);
    }

    public TailHandler getTailHandler() {
        return tailHandler;
    }

    public Integer getIndex(String handlerName, Integer order) {
        for (int i = 0; i < handlerContexts.length; i++) {
            if (handlerName.equals(handlerContexts[i].name()) && order == handlerContexts[i].order()) {
                return i;
            }
        }
        return null;
    }

    public Handler getDefaultHeadHandler() {
        return defaultHeadHandler;
    }

    public void setDefaultHeadHandler(Handler defaultHeadHandler) {
        this.defaultHeadHandler = defaultHeadHandler;
    }
}
